/*
 * ariter
 */

const getMatrix = [
  ['55', '55', '56', '56', '57', '57', '58', '58', '59', '59'], //这一行是读A1M0-A1M9
  ['5A', '5A', '5B', '5B', '5C', '5C', '5D', '5D', '5E', '5E'], //这一行是读A2M0-A2M9
]
const setMatrix = [
  ['65', '65', '66', '66', '67', '67', '68', '68', '69', '69'], //这一行是写A1M0-A1M9
  ['6A', '6A', '6B', '6B', '6C', '6C', '6D', '6D', '6E', '6E'], //这一行是写A2M0-A2M9
]
let readRef = []
function getCmd(type) {
  if (type === 'heartbeat') {
    return ['03', '51', '0D'] //读实时扭矩 实时角度峰值扭矩 实时角度 电量
  } else if (type === 'arg') {
    return ['03', '5F', '0C'] //读设备参数
  } else if (type === 'critical') {
    return ['03', getMatrix[0][0], '0C'] //读取临界参数
  } else {
    let pos = type.match(/\d/g)
    if (!pos) return [] /* throw new Error('参数错误') */
    let len = pos[0] == 2 && pos[1] > 1 ? '0E' : '0C'
    return ['03', getMatrix[pos[0] - 1][pos[1]], len]
  }
}
function setCmd(type) {
  if (type === 'clear') {
    return ['06', '61', '00'] //清零
  } else if (type === 'close') {
    return ['06', '62', '00'] //关机
  } else if (type == 'arg') {
    //设置设备参数
    // return ['06','63', '05']
    return ['06', '63', '0C']
  } else {
    let len
    let pos = type.match(/\d/g)
    if (!pos) return [] /* throw new Error('参数错误') */
    if (pos[0] == 1 && (pos[1] == 0 || pos[1] == 1)) {
      len = '09'
    } else if (pos[0] == 2 && (pos[1] == 0 || pos[1] == 1)) {
      len = '0C'
    } else if (pos[0] == 2 && pos[1] > 1) {
      len = '0E'
    } else {
      len = '0C'
    }
    return ['06', setMatrix[pos[0] - 1][pos[1]], len]
    // let len = pos[0] == 2 && pos[1] > 1 ? '0E' : '0C';
  }
}
// 格式化值 将16进制的数：低位放高位，设置指令时是：XL XH
function formatVal(n) {
  let hex = n.length % 2 ? '0' + n : n
  return hex
    .split(/(.{2})/g)
    .filter((v) => v)
    .reverse()
}
// 格式化扭矩 为 16进制数,并按地位在前高位在后排列，以便转换成硬件接受的指令给扳手
function formatTork(val) {
  let hex = Math.round(val * 100).toString(16)
  return [...formatVal(hex), '00'].splice(0, 3)
}
// 格式化角度 为 16进制数
function formatAngle(val) {
  let hex = (val * 10).toString(16)
  return [...formatVal(hex), '00'].splice(0, 2)
}
// 获取设置模式命令
function setModeCmd(sendData) {
  console.log('Modecmd', sendData)
  // const {worktype_name, tork_unit} = sendData;
  const { worktype, tork_unit } = sendData
  let unitMpa = ['nm', 'ftlb', 'inlb', 'kgfcm'].map((v) => v.toLowerCase())

  // A1,A2模式 00 = A1模式(扭矩模式) 01 = A2模式(角度模式)
  // let modeA = (worktype_name.charAt(1).slice(-1) - 1).toString(16).padStart(2, '0');
  let modeA = (worktype.charAt(1).slice(-1) - 1).toString(16).padStart(2, '0')

  // P/T模式 00 = T模式(追随模式); 01 = P模式(峰值模式)
  let pt = '01'

  // 扭矩单位 00 = N·m; 01 = lbf·in; 02 = lbf·ft; 03 = kgf·cm
  let unit = unitMpa.indexOf(tork_unit.toLowerCase()).toString(16).padStart(2, '0')

  // M0 - M9 => 00,01,02,03,04,05,06,07,08,09
  // let modeM = worktype_name.charAt(3).slice(-1).toString(16).padStart(2, '0');
  let modeM = worktype.charAt(3).slice(-1).toString(16).padStart(2, '0')

  // 角度挡位 0 = 15°/s,4 = 250°/s, 1 = 30°/s, 5 = 500°/s, 2 = 60°/s, 6 = 1000°/s, 3 = 120°/s,7 = 2000°/s
  let angle = '00'

  // 06 63 05 (01) (01) (01) (01) (01) XL XH
  // A1A2模式,PT模式,单位,M0~M9模式,角度挡位
  let cmd = setCmd('arg')
  cmd.push(...[modeA, pt, modeM, unit, angle])
  // let verifyEnd = crc16modbus(cmd)
  // cmd.push(...verifyEnd)
  // console.log('设置模式:', cmd.join(' '))
  // return arrayToBuffer(cmd)
  return cmd
}
// 获取发送数据的buffer
function getSendDataCmd(sendData) {
  console.log('senddata', sendData)
  // let {worktype_name, target_tork, max_tork, min_tork, angle, max_angle, min_angle} = sendData;
  let { worktype, target_tork, max_tork, min_tork, angle, max_angle, min_angle } = sendData

  // sendData['readData']=wx.$readRef[worktype_name];
  // wx.$sendData = {"worktype_name": "A1M0", "target_tork": "15.2", "tork_unit": "Nm", "min_tork": "399.8", "max_tork": "400.2", "angle": "0.0", "min_angle": "0.0", "max_angle": "0.0", "workmanship_id": "4"};

  // 模式 A1 是扭矩模式；A2 是角度模
  // let cmdMode = wx.$utils.cmd.set(worktype_name);
  let cmdMode = setCmd(worktype)
  // let readMode = wx.$utils.cmd.get(worktype_name);

  let torqueArr = formatTork(target_tork)
  // console.log('目标扭矩：', target_tork, torqueArr);
  let torqueMaxArr = formatTork(max_tork)
  // console.log('扭矩上限：', max_tork, torqueMaxArr);
  let torqueMinArr = formatTork(min_tork)
  // console.log('扭矩下限：', min_tork, torqueMinArr);
  let angleArr = formatAngle(angle)
  // console.log('目标角度：', angle, angleArr);
  let angleMinArr = formatAngle(min_angle)
  // console.log('角度下限', min_angle, angleMinArr);
  let angleMaxArr = formatAngle(max_angle)
  // console.log('角度上限', max_angle, angleMaxArr);
  let cmd = [...cmdMode]
  // let modeM = worktype_name.slice(-1);
  let modeM = worktype.slice(-1)
  let placeholder = (num) => new Array(num).fill('00')
  let cmdData = []
  // if (worktype_name.startsWith('A1')) {
  if (worktype.startsWith('A1')) {
    cmdData = modeM == 0 ? [...torqueArr] : [...torqueMinArr, ...torqueMaxArr]
    // console.log('cmdData',cmdData);
    if (modeM == 0) {
      // console.log('readRef0')
      cmdData.push(...placeholder(6))
    } else if (modeM == 1) {
      // 一个扭矩用三个字节表示
      // cmdData[modeM % 2 === 0 ? 'push' : 'unshift'](...placeholder(3)); //条件满足则将cmdData数组push(...placehode(3))
      cmdData.unshift(...placeholder(3))
      // console.log('readRef1:')
    } else if (modeM % 2 == 0 && modeM != 0) {
      readRef = cmdData.slice() //保存偶数设置的数据，以便下一个奇数设置时需要设置（一条指令其实是设置偶数及奇数一对）
      // console.log('readRef2:')
      cmdData.push(...placeholder(6))
    }
    // cmdData[modeM % 2 === 0 ? 'push' : 'unshift'](...placeholder(6));
    else if (modeM % 2 != 0 && modeM != 1) {
      if (readRef.length !== 0) {
        console.log('readRef3r:')
        cmdData.unshift(...readRef)
      } else {
        console.log('readRef3:')
        cmdData.unshift(...placeholder(6))
      }
    }
  }
  console.log('cmdData:', cmdData)
  // A2M0只传 目标扭矩 目标角度； A2M其他模式传 目标扭矩 角度下限 角度上限 [小值在前，大值在后]
  // if (worktype_name.startsWith('A2')) {
  if (worktype.startsWith('A2')) {
    cmdData =
      modeM == 0 ? [...torqueArr, ...angleArr] : [...torqueArr, ...angleMinArr, ...angleMaxArr]
    if (modeM == 1) {
      cmdData.unshift(...placeholder(5))
    } else if (modeM == 0) {
      cmdData.push(...placeholder(7))
    } else {
      // cmdData[modeM % 2 === 0 ? 'push' : 'unshift'](...placeholder(6));
      if (modeM % 2 == 0 && modeM != 0) {
        readRef = cmdData.slice()
        cmdData.push(...placeholder(7))
      } else if (modeM % 2 != 0 && modeM != 1) {
        if (readRef.length === 0) cmdData.unshift(...placeholder(7))
        else cmdData.unshift(...readRef)
      }
    }

    //下面是原来读取了扳手的数据后在下发的不可行方法：
    // A1M0只传 目标扭矩；A1M其他模式传 扭矩下限 扭矩上限
    // if (worktype_name.startsWith('A1')) {
    //   cmdData = (modeM == 0 ? [...torqueArr] : [...torqueMinArr, ...torqueMaxArr]);
    //   if (modeM == 1) {
    //     // 一个扭矩用三个字节表示
    //     // cmdData[modeM % 2 === 0 ? 'push' : 'unshift'](...placeholder(3)); //条件满足则将cmdData数组push(...placehode(3))
    //     cmdData.unshift(...sendData['readData'].slice(0,3)); //将原来M0数据保留，放在当前要设置的数据前面
    //   }
    //   else if (modeM == 0){
    //     cmdData.push(...sendData['readData'].slice(3,9)); //将原来M1数据保留，放在当前要设置的数据后面
    //   } else {
    //     // cmdData[modeM % 2 === 0 ? 'push' : 'unshift'](...placeholder(6));
    //     if (modeM % 2 === 0){
    //       cmdData.push(...sendData['readData'].slice(6,12));//将原来同指令的单数模式的数据保留，放在当前要设置的数据后面
    //     }
    //     else {
    //       cmdData.unshift(...sendData['readData'].slice(0,6));//将原来同指令的双数模式的数据保留，放在当前要设置的数据前面
    //     }
    //   }
    // }
    // console.log('cmdData:',cmdData);
    // // A2M0只传 目标扭矩 目标角度； A2M其他模式传 目标扭矩 角度下限 角度上限 [小值在前，大值在后]
    // if (worktype_name.startsWith('A2')) {
    //   cmdData = modeM == 0 ? [...torqueArr, ...angleArr] : [...torqueArr, ...angleMinArr, ...angleMaxArr];
    //   if (modeM == 1) {
    //     cmdData.unshift(...sendData['readData'].slice(0,5)); //将原来M0数据保留，放在当前要设置的数据前面
    //   }
    //   else if (modeM == 0){
    //     cmdData.push(...sendData['readData'].slice(5,12)); //将原来M1数据保留，放在当前要设置的数据后面
    //   } else {
    //     // cmdData[modeM % 2 === 0 ? 'push' : 'unshift'](...placeholder(6));
    //     if (modeM % 2 === 0){
    //       cmdData.push(...sendData['readData'].slice(7,14));//将原来同指令的单数模式的数据保留，放在当前要设置的数据后面
    //     }
    //     else {
    //       cmdData.unshift(...sendData['readData'].slice(0,7));//将原来同指令的双数模式的数据保留，放在当前要设置的数据前面
    //     }
    //   }

    // if (modeM == 1) {
    //   cmdData[modeM % 2 === 0 ? 'push' : 'unshift'](...placeholder(5));
    // } else {
    //   cmdData[modeM % 2 === 0 ? 'push' : 'unshift'](...placeholder(7));
    // }
  }
  // if (i+1 === length){
  //   this.readRef=[];
  // }
  // console.log('this.readRef',this.readRef,i,length);
  // let cmdLen = cmdData.length.toString(16).padStart(2, '0');
  // cmd.push(cmdLen)
  cmd.push(...cmdData)

  // let verifyEnd = crc16modbus(cmd)
  // cmd.push(...verifyEnd)
  console.log('发送命令:', cmd.join(' '))
  // const buffer = arrayToBuffer(cmd)
  // return buffer
  return cmd
}
// 批量发送
function getSendOrderBatchCmd(orders) {
  const cmd = []
  for (const order of orders) {
    cmd.push(getSendDataCmd(order))
  }
  return cmd
}

// 获取读取命令
// getReadCmd(sendData) {
//   console.log('sendData:', sendData)
//   // let {worktype_name} = sendData;
//   let { worktype } = sendData
//   // let cmd = wx.$utils.cmd.get(worktype_name);
//   let cmd = this.get(worktype)
//   // let verifyEnd = crc16modbus(cmd)
//   // cmd.push(...verifyEnd)
//   console.log(`读取${worktype}模式指令:`, cmd)
//   // const buffer = arrayToBuffer(cmd)
//   // return buffer
//   return cmd
// },

// function arrayToBuffer(arr) {
//   let cmd = arr.map((v) => '0x' + v)
//   // console.log("arrayToBuffer", cmd)
//   let uint16arr = new Uint8Array(cmd)
//   return uint16arr.buffer //返回由 Uint8Array引用的 ArrayBuffer
// }

// 读取设备报警参数 临界值
function readDeviceCriticalValue(arr, worktype = 'A1M1') {
  console.log('readDeviceCriticalValue-arr,worktype', arr, worktype)
  const cmdArr = getCmd(worktype)
  const isTrue = cmdArr.toString().toLowerCase() === arr.slice(0, 3).toString().toLowerCase()
  if (!isTrue) {
    uni.showToast({ title: '数据错误', icon: 'none' })
    return
  }

  const max_tork = (parseInt([arr[14], arr[13], arr[12]].join(''), 16) / 100).toFixed(2)
  const min_tork = max_tork / 10

  console.log('res:', {
    min_tork,
    max_tork,
  })
  return {
    min_tork,
    max_tork,
  }
}

// 格式化设备数据
function formatDeviceData(arr) {
  let d = new Date()
  let datetime = d.toJSON().substring(0, 19).replace('T', ' ')
  let datetime1 =
    [
      d.getFullYear(),
      (d.getMonth() + 1).toString().padStart(2, '0'),
      d.getDate().toString().padStart(2, '0'),
    ].join('-') +
    ' ' +
    [
      d.getHours().toString().padStart(2, '0'),
      d.getMinutes().toString().padStart(2, '0'),
      d.getSeconds().toString().padStart(2, '0'),
    ].join(':')

  let res = {
    // 工作时间
    datetime_work: datetime,
    datetime_work1: datetime1,
    // 扭矩 设备返回来的数据
    tork: '',
    // min_tork: '',
    max_tork: '',
    // 角度 设备返回来的数据
    angle: '',
    // min_angle: '',
    max_angle: '',
    // 扳手设备ID TODO:
    // wrench_identity: '',
    // 单位
    unit: '',
  }

  let tork = ['0x', arr[5], arr[4], arr[3]].join('')
  tork = tork == '0x000000' ? 0 : tork
  let max_tork = ['0x', arr[10], arr[9], arr[8]].join('')
  max_tork = max_tork == '0x000000' ? 0 : max_tork

  let angle = ['0x', arr[7], arr[6]].join('')
  angle = angle == '0x0000' ? 0 : angle
  let max_angle = ['0x', arr[12], arr[11]].join('')
  max_angle = max_angle == '0x0000' ? 0 : max_angle

  let unit = (['0x', arr[14]].join('') >> 2) & 0x03

  res.tork = tork ? (parseInt(tork, 16) / 100).toFixed(2) : null
  res.max_tork = max_tork ? (parseInt(max_tork, 16) / 100).toFixed(2) : null

  res.angle = angle ? (parseInt(angle, 16) / 10).toFixed(2) : null
  res.max_angle = max_angle ? (parseInt(max_angle, 16) / 10).toFixed(2) : null

  res.unit = ['Nm', 'lbfin', 'lbfft', 'kgfcm'][unit] || 'ERROR'
  console.log('formatDeviceData', JSON.stringify(res))

  return res
}

// CRC-16/MODBUS 校验
// function crc16modbus(data) {
//   const dataBytes = data.map((v) => parseInt(v, 16))

//   let crc = 0xffff
//   const polynomial = 0xa001 // This is the polynomial x^16 + x^15 + x^2 + 1

//   for (const byte of dataBytes) {
//     crc ^= byte
//     for (let i = 0; i < 8; i++) {
//       if (crc & 0x0001) {
//         crc = ((crc >> 1) ^ polynomial) & 0xffff
//       } else {
//         crc >>= 1
//       }
//     }
//   }

//   return crc.toString(16).toUpperCase().padStart(4, '0').match(/\w{2}/g).reverse()
// }
export default {
  cmd: {
    setCmd,
    getCmd,
    // getInitReadCmd,
    setModeCmd,
    getSendDataCmd,
    getSendOrderBatchCmd,
  },
  readDeviceCriticalValue,
  formatDeviceData,
}
